﻿using System.Collections.Concurrent;
using System.Reflection;

namespace DesignModeConsole.行为型.观察者模式.EventBusSample;

/// <summary>
/// 事件总线的实现
/// </summary>
public class EventBus : IEventBus
{
    /// <summary>
    /// 存储字典  key：数据类型FullName  value：处理程序类型
    /// </summary>
    private static readonly ConcurrentDictionary<string, List<Type>> _dicEvent = new();

    /// <summary>
    /// 注册以及取消注册的时候需要加锁处理
    /// </summary>
    private static readonly object _obj = new object();

    public EventBus()
    {
        InitRegister();
    }

    /// <summary>
    /// 初始化注册
    /// </summary>
    private void InitRegister()
    {
        lock (_obj)
        {
            if (!_dicEvent.IsEmpty)
            {
                return;
            }
        }

        //自动扫描文件夹下的程序集中指定的类型并且注册
        var baseType = typeof(IEventHandler<>);
        var ignoreNameSpaces = new string[] { "Microsoft.", "System." };
        foreach (var file in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll"))
        {
            var ass = Assembly.LoadFrom(file);
            // 查询到实现接口IEventHandler<>的方法 排除系统默认的ignoreNameSpaces开头的程序集
            foreach (var item in ass.GetTypes()
                         .Where(p => !ignoreNameSpaces.Any(t =>
                                         p.FullName != null && p.FullName.StartsWith(t)) &&
                                     IsAssignableToOpenGenericType(p, baseType) &&
                                     !p.IsAbstract &&
                                     p.IsClass))
            {
                foreach (var item1 in item.GetInterfaces())
                {
                    foreach (var item2 in item1.GetGenericArguments())
                    {
                        if (item2.GetInterfaces().Contains(typeof(EventData)))
                        {
                            Register(item2, item);
                        }
                    }
                }
            }
        }
    }


    #region 注册事件

    public void Register<TEventData>(Type handlerType) where TEventData : EventData
    {
        //将数据存储到mapDic
        var dataType = typeof(TEventData).FullName;
        Register(dataType, handlerType);
    }

    public void Register(Type eventType, Type handlerType)
    {
        var dataType = eventType.FullName;
        Register(dataType, handlerType);
    }

    public void Register(string pubKey, Type? handlerType)
    {
        lock (_obj)
        {
            //将数据存储到dicEvent
            if (_dicEvent.ContainsKey(pubKey) == false)
            {
                _dicEvent[pubKey] = new List<Type>();
            }

            if (handlerType is null)
                return;

            if (_dicEvent[pubKey].Exists(p => p.GetType() == handlerType) == false)
            {
                _dicEvent[pubKey].Add(handlerType);
            }
        }
    }

    #endregion

    #region 取消事件注册

    public void Unregister<TEventData>(Type handler) where TEventData : EventData
    {
        var dataType = typeof(TEventData);
        Unregister(dataType, handler);
    }

    public void Unregister(Type eventType, Type handlerType)
    {
        var key = eventType.FullName;
        Unregister(key, handlerType);
    }

    public void Unregister(string eventType, Type handlerType)
    {
        lock (_obj)
        {
            if (!_dicEvent.ContainsKey(eventType))
            {
                return;
            }

            if (_dicEvent[eventType].Exists(p => p.GetType() == handlerType))
            {
                _dicEvent[eventType].Remove(_dicEvent[eventType].Find(p => p.GetType() == handlerType));
            }
        }
    }

    #endregion

    #region Trigger触发

    public void Trigger<TEventData>(TEventData eventData) where TEventData : EventData
    {
        var dataType = eventData.GetType().FullName;
        //获取当前的EventData绑定的所有Handler
        Notify(dataType, eventData);
    }

    public void Trigger(string pubKey, EventData eventData)
    {
        //获取当前的EventData绑定的所有Handler
        Notify(pubKey, eventData);
    }

    public async Task TriggerAsync<TEventData>(TEventData eventData) where TEventData : EventData
    {
        await Task.Factory.StartNew(() =>
        {
            var dataType = eventData.GetType().FullName;
            Notify(dataType, eventData);
        });
    }

    public async Task TriggerAsync(string pubKey, EventData eventData)
    {
        await Task.Factory.StartNew(() =>
        {
            Notify(pubKey, eventData);
        });
    }

    //通知每成功执行一个就需要记录到数据库
    private void Notify<TEventData>(string eventType, TEventData eventData) where TEventData : EventData
    {
        //获取当前的EventData绑定的所有Handler
        var handlerTypes = _dicEvent[eventType];
        foreach (var handlerType in handlerTypes)
        {
            var handler = Activator.CreateInstance(handlerType) as IEventHandler<TEventData>;
            handler?.Handle(eventData);
        }
    }

    #endregion

    /// <summary> 
    /// 一个类是否继承自另外一个类型
    /// </summary>
    /// <param name="givenType"></param>
    /// <param name="genericType"></param>
    /// <returns></returns>
    private bool IsAssignableToOpenGenericType(Type givenType, Type genericType)
    {
        if (givenType.GetInterfaces().Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == genericType))
        {
            return true;
        }

        if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
            return true;
        var baseType = givenType.BaseType;
        return baseType != null && IsAssignableToOpenGenericType(baseType, genericType);
    }
}